#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Project ：tools 
@File ：批量生成文件夹和文件.py
@IDE  ：PyCharm 
@Author ：李涵彬
@Date ：2025/1/20 18:54 
"""

"""
批量生成文件夹和文件的程序
"""
import os
import random
import string
import logging
import concurrent.futures
from pathlib import Path
from tkinter import Tk, Label, Entry, Button, messagebox, filedialog
from tkinter.ttk import Progressbar, Style
import threading
import queue
from typing import Generator

# 配置日志记录
logging.basicConfig(filename="./logs/generation_errors.log", level=logging.ERROR,
                    format="%(asctime)s - %(levelname)s - %(message)s")


def random_string(length: int) -> str:
    """
    生成指定长度的随机字符串
    :param length: 字符串长度
    :return: 随机字符串
    """
    letters = string.ascii_letters + string.digits
    return ''.join(random.choice(letters) for _ in range(length))


def create_small_file(directory: Path) -> Path:
    """
    在指定目录下创建一个固定内容的小文件
    :param directory: 文件夹路径
    :return: 文件路径
    """
    file_name = random_string(8) + "." + random_string(3)  # 随机文件名和后缀
    file_path = directory / file_name
    with open(file_path, "w") as file:
        file.write("This is a small file.\n")  # 写入固定内容
    return file_path


def create_random_folder(directory: Path) -> Path:
    """
    在指定目录下创建一个随机名称的文件夹
    :param directory: 父目录路径
    :return: 新创建的文件夹路径
    """
    folder_name = random_string(8)
    folder_path = directory / folder_name
    folder_path.mkdir()
    return folder_path


def generate_files_in_folder(folder_path: Path, num_files: int, progress_queue: queue.Queue) -> None:
    """
    在一个文件夹中生成指定数量的文件
    :param folder_path: 文件夹路径
    :param num_files: 文件数量
    :param progress_queue: 用于线程间通信的队列
    """
    for _ in range(num_files):
        create_small_file(folder_path)
        progress_queue.put(("update", 1))  # 修改为元组格式


def generate_files_and_folders(root_dir: str, num_folders: int, num_files_per_folder: int, progress_queue: queue.Queue) -> None:
    """
    在根目录下生成文件夹和文件
    :param root_dir: 根目录路径
    :param num_folders: 文件夹数量
    :param num_files_per_folder: 每个文件夹中的文件数量
    :param progress_queue: 用于线程间通信的队列
    """
    root_path = Path(root_dir)
    root_path.mkdir(parents=True, exist_ok=True)  # 确保根目录存在

    total_tasks = num_folders * num_files_per_folder
    progress_queue.put(("max", total_tasks))  # 设置进度条最大值

    with concurrent.futures.ThreadPoolExecutor() as executor:
        futures = []
        for _ in range(num_folders):
            folder_path = create_random_folder(root_path)
            futures.append(executor.submit(generate_files_in_folder, folder_path, num_files_per_folder, progress_queue))

        # 等待所有任务完成
        for future in concurrent.futures.as_completed(futures):
            try:
                future.result()
            except Exception as e:
                logging.error(f"Error during file generation: {e}")
                progress_queue.put(("error", f"Error: {e}"))  # 发送错误信息

    progress_queue.put(("complete", "File generation completed successfully."))  # 发送完成信号


def update_progress(progress_queue: queue.Queue, progress_bar: Progressbar, status_label: Label) -> None:
    """
    更新进度条和状态标签
    :param progress_queue: 用于线程间通信的队列
    :param progress_bar: 进度条组件
    :param status_label: 状态标签组件
    """
    while True:
        message = progress_queue.get()
        if isinstance(message, tuple):  # 确保消息是元组
            action, value = message
            if action == "max":
                progress_bar["maximum"] = value  # 设置进度条最大值
            elif action == "update":
                progress_bar["value"] += value  # 更新进度条值
                status_label.config(text=f"正在生成... ({progress_bar['value']}/{progress_bar['maximum']})")
            elif action == "complete":
                status_label.config(text="生成完成。")
                messagebox.showinfo("完成", value)  # 弹出完成提示
                break
            elif action == "error":
                status_label.config(text="发生错误，请查看日志。")
                messagebox.showerror("错误", value)  # 弹出错误提示
        else:
            logging.error(f"Invalid message format in queue: {message}")
            messagebox.showerror("错误", "程序内部错误，请查看日志文件。")
            break


class FileGenerationApp:
    """
    文件生成程序的GUI界面类
    """

    def __init__(self, root: Tk) -> None:
        self.root = root
        self.root.title("文件生成程序")
        self.root.geometry("600x400")  # 设置窗口大小

        self.progress_queue = queue.Queue()  # 创建线程间通信队列
        self.setup_ui()  # 初始化界面

    def setup_ui(self) -> None:
        """
        初始化GUI界面
        """
        # 样式
        style = Style()
        style.theme_use("default")
        style.configure("TProgressbar", thickness=20, background="#4caf50")

        # 标签
        Label(self.root, text="请输入根目录路径:", font=("Arial", 12)).pack(pady=10)

        # 输入框
        self.entry = Entry(self.root, width=50, font=("Arial", 12))
        self.entry.pack(pady=10)

        # 选择文件夹按钮
        browse_button = Button(self.root, text="浏览", command=self.browse_folder, font=("Arial", 12))
        browse_button.pack(pady=10)

        # 文件夹数量和文件数量输入
        Label(self.root, text="文件夹数量:", font=("Arial", 12)).pack()
        self.folder_count = Entry(self.root, width=10, font=("Arial", 12))
        self.folder_count.insert(0, "10")
        self.folder_count.pack()

        Label(self.root, text="每个文件夹中的文件数量:", font=("Arial", 12)).pack()
        self.file_count = Entry(self.root, width=10, font=("Arial", 12))
        self.file_count.insert(0, "10")
        self.file_count.pack()

        # 进度条
        self.progress_bar = Progressbar(self.root, orient="horizontal", length=500, mode="determinate", style="TProgressbar")
        self.progress_bar.pack(pady=20)

        # 状态标签
        self.status_label = Label(self.root, text="", font=("Arial", 12))
        self.status_label.pack(pady=10)

        # 生成文件按钮
        generate_button = Button(self.root, text="生成文件和文件夹", command=self.start_generation, font=("Arial", 12))
        generate_button.pack(pady=20)

        # 启动进度更新线程
        threading.Thread(target=update_progress, args=(self.progress_queue, self.progress_bar, self.status_label), daemon=True).start()

    def browse_folder(self) -> None:
        """
        选择文件夹并更新输入框
        """
        folder_path = filedialog.askdirectory()
        if folder_path:
            self.entry.delete(0, 'end')
            self.entry.insert(0, folder_path)

    def start_generation(self) -> None:
        """
        开始生成文件和文件夹
        """
        root_dir = self.entry.get()
        if not root_dir:
            messagebox.showwarning("警告", "请输入目录路径。")
            return
        if not os.path.exists(root_dir):
            os.makedirs(root_dir)

        num_folders = int(self.folder_count.get())
        num_files_per_folder = int(self.file_count.get())

        threading.Thread(target=generate_files_and_folders, args=(root_dir, num_folders, num_files_per_folder, self.progress_queue), daemon=True).start()


if __name__ == "__main__":
    root = Tk()
    app = FileGenerationApp(root)
    root.mainloop()